import 'package:orginone/dart/base/common/commands.dart';
import 'package:orginone/dart/base/schema.dart';
import 'package:orginone/dart/core/public/collection.dart';
import 'package:orginone/dart/core/provider/index.dart';
import 'package:orginone/main.dart';
import 'package:uuid/uuid.dart';

// 暂存箱
abstract class IBoxProvider {
  // 使用箱子的用户
  late DataProvider provider;
  // 暂存的物品
  late List<XStaging> stagings;
  // 获取同一类物品
  List<XStaging> groups(List<String> typeNames);
  // 获取关系物品
  List<XStaging> relations(String relations, List<String> typeNames);

  /// 放入物品
  Future<XStaging?> createStaging(XStaging data);

  /// 拿出物品
  Future<bool> removeStaging(List<XStaging> data);

  /// 查看所有物品
  Future<List<XStaging>> loadStagings([bool? reload]);
}

class BoxProvider implements IBoxProvider {
  BoxProvider(this.provider) {
    key = const Uuid().v1();
    coll?.subscribe(
      [key],
      (message) {
        switch (message['operate']) {
          case 'create':
            stagings.addAll(message['data']);
            break;
          case 'delete':
            {
              List ids = message['data'].map((item) => item.id).toList();
              stagings =
                  stagings.where((item) => !ids.contains(item.id)).toList();
            }
            break;
        }
        command.emitter('stagings', 'refresh');
      },
    );
  }

  late String key;
  @override
  DataProvider provider;
  @override
  List<XStaging> stagings = [];
  bool _stagingLoaded = false;

  XCollection<XStaging>? get coll {
    return provider.user?.resource.stagingColl;
  }

  @override
  List<XStaging> groups(List<String> typeNames) {
    return stagings.where((item) => typeNames.contains(item.typeName)).toList();
  }

  @override
  List<XStaging> relations(String relations, List<String> typeNames) {
    return stagings
        .where((item) =>
            item.relations == relations && typeNames.contains(item.typeName))
        .toList();
  }

  @override
  Future<XStaging?> createStaging(XStaging data) async {
    var res = await coll?.insert(data);
    if (null != res) {
      await coll?.notity({
        'data': [res],
        'operate': 'create'
      });
      return res;
    }
    return null;
  }

  @override
  Future<bool> removeStaging(List<XStaging> data) async {
    var res = await coll?.removeMany(data);
    if (null != res) {
      res = await coll?.notity({'data': data, 'operate': 'delete'});
      return res ?? false;
    }
    return false;
  }

  @override
  Future<List<XStaging>> loadStagings([bool? reload]) async {
    if (!_stagingLoaded || null != reload) {
      var res = await coll?.all(reload: reload ?? false);
      if (null != res) {
        _stagingLoaded = true;
        stagings = res;
        await _loadThings(groups(['实体']));
        command.emitter('stagings', 'refresh');
      }
    }
    return stagings;
  }

  Future<List<XStaging>> _loadThings(List<XStaging> stagings) async {
    Map<String, List<XStaging>> groups =
        stagings.fold(<String, List<XStaging>>{}, (prev, item) {
      (prev[item.relations] ??= []).add(item);
      return prev;
    });
    for (var key in groups.keys) {
      var keyWords = key.split(':');
      if (keyWords.length <= 1) {
        continue;
      }
      var res = await kernel
          .loadThing(keyWords[0], keyWords[0], keyWords[1].split('-'), {
        'options': {
          'match': {
            'id': {'_in_': groups[key]?.map((item) => item.data.id)}
          },
        },
      });
      if (res.data) {
        for (var staging in groups[key]!) {
          for (var thing in res.data) {
            if (staging.data.id == thing.id) {
              staging.data = thing;
              break;
            }
          }
        }
      }
    }
    return stagings;
  }
}
